package com.ymt.bpm.web;

import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.ymt.bpm.util.Const;
import com.ymt.bpm.util.JwtUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by Johnny on 2017/11/26.
 */
public class AdminWebJwtFilter extends OncePerRequestFilter {

    private Logger log = LoggerFactory.getLogger(this.getClass());

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        HttpServletRequest req = (HttpServletRequest)request;
        boolean ignore = ignore(request.getContextPath(), request.getRequestURI());
        if (!ignore) {
            if (log.isTraceEnabled()) {
                log.trace("admin doFilterInternal getContextPath "+request.getContextPath());
                log.trace("admin doFilterInternal getRequestURI "+request.getRequestURI());
            }
        }
        if (ignore || checkAuthHeader(req, response)) {
            filterChain.doFilter(request, response);
        } else {
            //save request
            StringBuffer successUrl = new StringBuffer(request.getRequestURI());
            if (request.getQueryString()!=null) {
                successUrl.append("?").append(request.getQueryString());
            }
            if (log.isTraceEnabled()) {
                log.trace("admin doFilterInternal successUrl "+successUrl.toString());
            }
            request.getSession().setAttribute("successUrl", successUrl.toString());

            //redirect login by spring security
            filterChain.doFilter(request, response);
        }
    }

    private boolean checkAuthHeader(HttpServletRequest req, HttpServletResponse response) {
        /*
        //get jwt token from header
        String jwtToken = req.getHeader("Authorization");
        if (jwtToken==null || !jwtToken.startsWith("JWT ")) {
            return false;
        }
        jwtToken = jwtToken.substring(4);*/

        //get jwt token from cookie
        String jwtToken = null;
        Cookie[] cookies = req.getCookies();
        if (cookies!=null) {
            for (Cookie cookie:cookies) {
                if (Const.JWT_TOKEN.equalsIgnoreCase(cookie.getName())) {
                    jwtToken = cookie.getValue();
                    break;
                }
            }
        }
        if (jwtToken!=null) {
            DecodedJWT jwt = JwtUtil.decode(jwtToken);
            if (jwt!=null) {
                Map<String, String> detail = new HashMap<String, String>();
                String loginName = jwt.getSubject();
                detail.put(Const.LOGINNAME, loginName);
                detail.put(Const.DISPLAYNAME, jwt.getClaim(Const.DISPLAYNAME).asString());
                detail.put(Const.LANG, jwt.getClaim(Const.LANG).asString());
//                req.setAttribute(Const.LOGINNAME, loginName);
//                req.setAttribute(Const.DISPLAYNAME, jwt.getClaim(Const.DISPLAYNAME).asString());
//                req.setAttribute(Const.LANG, jwt.getClaim(Const.LANG).asString());
                Claim tenantIdClaim = jwt.getClaim(Const.TENANT_ID);
                if (tenantIdClaim!=null) {
//                    req.setAttribute(Const.TENANT_ID, tenantIdClaim.asString());
                    detail.put(Const.TENANT_ID, tenantIdClaim.asString());
                }

                //set authentication
                SimpleGrantedAuthority sga = new SimpleGrantedAuthority("USERS");
                List<GrantedAuthority> gal = new ArrayList<GrantedAuthority>();
                gal.add(sga);
                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(loginName, null, gal);
                //authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(req));
                authentication.setDetails(detail);
                SecurityContextHolder.getContext().setAuthentication(authentication);

                //检查是否需要更新
                if (JwtUtil.aboutToExpire(jwt, 1800000L)) {//半小时之内过期
                    String newToken = JwtUtil.refreshTokenExpires(jwt);
                    //set new cookie
                    Cookie cookie = new Cookie(Const.JWT_TOKEN, newToken);
                    cookie.setHttpOnly(true);   //防XSS
                    cookie.setPath("/");
                    response.addCookie(cookie);
                }

                return true;
            }
        }
        return false;
    }

    private boolean ignore(String ctx, String uri) {
        String[] ignores = {"/favicon.ico",
                "/login",
                "/logout",
                ctx + "/favicon.ico",
                ctx + "/login",
                ctx + "/logout",
                ctx + "/openapi/",
                ctx + "/pages/",
                ctx + "/servlet/",
                "/bpmp-resources",
                "/fmd-resources",
                "/bpmp-engine"
        };

        for (String ig : ignores) {
            if (uri.startsWith(ig)) {
                return true;
            }
        }
        return false;
    }

}
